/*
 * Copyright (C) 2008 Romain Guy
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xbmc.android.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.xbmc.api.object.ICoverArt;
import org.xbmc.api.type.MediaType;
import org.xbmc.api.type.ThumbSize;
import org.xbmc.api.type.ThumbSize.Dimension;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;

public abstract class ImportUtilities {
	
    private static final String CACHE_DIRECTORY = "xbmc";
    private static final double MIN_FREE_SPACE = 3;

    public static File getCacheDirectory(String type, int size) {
    	StringBuilder sb = new StringBuilder(CACHE_DIRECTORY);
    	sb.append(type);
    	sb.append(ThumbSize.getDir(size));
        return IOUtilities.getExternalFile(sb.toString());
    }
    
    public static File getCacheFile(String type, int size, String name) {
    	StringBuilder sb = new StringBuilder(32);
    	sb.append(CACHE_DIRECTORY);
    	sb.append(type);
    	sb.append(ThumbSize.getDir(size));
    	sb.append("/");
    	sb.append(name);
    	return IOUtilities.getExternalFile(sb.toString());
    }

    public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSize) {
		Bitmap sizeToReturn = null;
		File cacheDirectory;
		final int mediaType = cover.getMediaType();
		for (int currentThumbSize : ThumbSize.values()) {
			// don't save big covers
			if (currentThumbSize == ThumbSize.BIG) {
				if (thumbSize == currentThumbSize) {
					return bitmap;
				} else {
					continue;
				}
			}
			
			try {
				cacheDirectory = ensureCache(MediaType.getArtFolder(mediaType), currentThumbSize);
			} catch (IOException e) {
				return null;
			}

			File coverFile = new File(cacheDirectory, Crc32.formatAsHexLowerCase(cover.getCrc()));
			FileOutputStream out = null;
			try {
				final Bitmap source = bitmap;

				// Centre crop and resize the image
				Dimension targetDim = ThumbSize.getTargetDimension(currentThumbSize, mediaType, source.getWidth(), source.getHeight());
				
				double targetAR = targetDim.x / targetDim.y;
				double sourceAR = source.getWidth() / source.getHeight(); 

				Bitmap cropped;
				if (sourceAR > targetAR) {
					int boundTop = 0;
					int boundLeft = (int) ((source.getWidth() - (source.getHeight() * targetAR)) / 2);
					int boundBottom = source.getHeight();
					int boundRight = (int) ((source.getWidth() + (source.getHeight() * targetAR)) / 2);
					cropped = Bitmap.createBitmap(source, boundLeft, boundTop, boundRight, boundBottom);
				} else if (sourceAR < targetAR) {
					int boundTop = (int) ((source.getHeight() - (source.getWidth() * targetAR)) / 2);
					int boundLeft = 0;
					int boundBottom = (int) ((source.getHeight() + (source.getWidth() * targetAR)) / 2);
					int boundRight = source.getWidth();
					cropped = Bitmap.createBitmap(source, boundLeft, boundTop, boundRight, boundBottom);
				} else {
					cropped = source;
				}

				Bitmap resized = Bitmap.createScaledBitmap(cropped, targetDim.x, targetDim.y, true);

				resized.compress(Bitmap.CompressFormat.JPEG, 85, new FileOutputStream(coverFile));
				if (thumbSize == currentThumbSize) {
					sizeToReturn = resized;
				}				
			} catch (FileNotFoundException e) {
				return null;
			} finally {
				IOUtilities.closeStream(out);
			}
		}
		
		return sizeToReturn;
	}
    
	public static int calculateSampleSize(BitmapFactory.Options options, Dimension targetDimension) {
		if (targetDimension.x == 0 || targetDimension.y == 0) {
			return 1;
		}
		Boolean scaleByHeight = Math.abs(options.outHeight - targetDimension.y) >= Math.abs(options.outWidth - targetDimension.x);
		if (options.outHeight * options.outWidth * 2 >= 200 * 200 * 2) {
			// Load, scaling to smallest power of 2 that'll get it <= desired dimensions
			double sampleSize = scaleByHeight ? options.outHeight / targetDimension.y : options.outWidth / targetDimension.x;
			return (int) Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d)));
		} else {
			return 1;
		}
	}
    
    /**
     * Returns number of free bytes on the SD card.
     * @return Number of free bytes on the SD card.
     */
    public static long freeSpace() {
    	StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        long blockSize = stat.getBlockSize();
        long availableBlocks = stat.getAvailableBlocks();
        return availableBlocks * blockSize;
    }
    
    /**
     * Returns total size of SD card in bytes.
     * @return Total size of SD card in bytes.
     */
    public static long totalSpace() {
    	StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
    	long blockSize = stat.getBlockSize();
        long totalBlocks = stat.getBlockCount();
    	return totalBlocks * blockSize;
    }
    
    public static String assertSdCard() {
    	if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
    		return "Your SD card is not mounted. You'll need it for caching thumbs.";
    	}
    	if (freePercentage() < MIN_FREE_SPACE) {
    		return "You need to have more than " + MIN_FREE_SPACE + "% of free space on your SD card.";
    	}
    	return null;
    }
    
    
    /**
     * Returns free space in percent.
     * @return Free space in percent.
     */
    public static double freePercentage() {
    	StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        long availableBlocks = stat.getAvailableBlocks();
        long totalBlocks = stat.getBlockCount();
        return (double)availableBlocks / (double)totalBlocks * 100;
    }

    private static File ensureCache(String type, int size) throws IOException {
        File cacheDirectory = getCacheDirectory(type, size);
        if (!cacheDirectory.exists()) {
            cacheDirectory.mkdirs();
            new File(cacheDirectory, ".nomedia").createNewFile();
        }
        return cacheDirectory;
    }
    
    public static void purgeCache() {
    	final int size[] = ThumbSize.values();
    	final int[] mediaTypes = MediaType.getTypes();
    	for (int i = 0; i < mediaTypes.length; i++) {
    		String folder = MediaType.getArtFolder(mediaTypes[i]);
    		for (int j = 0; j < size.length; j++) {
    			File cacheDirectory = getCacheDirectory(folder, size[j]);
    			if (cacheDirectory.exists() && cacheDirectory.isDirectory()) {
    				for (File file : cacheDirectory.listFiles()) {
    					file.delete();
    				}
    			}
    		}
    	}
    }
}
